﻿package net.wangit.view.unit.sum;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.wangit.MapList;
import net.wangit.context.ActionContext;
import net.wangit.context.ActionContextHelper;
import net.wangit.framework.session.AgileSession;
import net.wangit.framework.session.UnitSettings;
import net.wangit.framework.util.UnitDataUtil;
import net.wangit.jdbc.DB;
import net.wangit.jdbc.DBFactory;
import net.wangit.jdbc.QueryParameters;
import net.wangit.util.Checker;
import net.wangit.util.StringUtil;
import net.wangit.view.unit.UnitComponent;


public class SumConfig {

	private static final String S1 = "S1{";
	private static final String S2 = "S2{";
	private static final String S3 = "S3{";
	private static final String C1 = "C1{";
	private static final String C2 = "C2{";
	private static final String C3 = "C3{";
	private static final String A1 = "A1{";
	private static final String A2 = "A2{";
	private static final String A3 = "A3{";
	private static final String P1 = "P1{";
	private static final String P2 = "P2{";
	private static final String P3 = "P3{";
	private static final String HEAD = "{";
	private static final String TAIL = "}";
	private int begin;
	private List<SumItem> items;
	private List rows;

	public SumConfig(ActionContext ac, UnitComponent uc) throws Exception {
		begin = 0;
		items = new ArrayList<SumItem>();
		rows = new ArrayList();
		AgileSession session = ActionContextHelper.getSession(ac);
		UnitSettings us = session.getUnitSettings(uc.getDomain(), uc.getId());
		int listSize = uc.getListSize();
		int maxSize = us.getMaxSize();
		int pageNumber = us.getPageNumber();
		MapList data = uc.getData();
		int end = data.size();
		String sumConfigString = uc.getSumConfig();
		if ((sumConfigString.indexOf(SumConfig.S3) >= 0 || sumConfigString
				.indexOf(SumConfig.C3) >= 0)
				&& maxSize > end) {
			begin = (pageNumber - 1) * listSize;
			end = pageNumber * listSize;
			DB db = DBFactory.getDB(uc.getDatasource());
			String sql = UnitDataUtil.getSql(ac, uc, db);
			data = db.query(sql);
			resetData(uc, data, listSize, pageNumber);
		} else if ((sumConfigString.indexOf(SumConfig.S2) >= 0 || sumConfigString
				.indexOf(SumConfig.C2) >= 0)
				&& pageNumber > 1) {
			begin = (pageNumber - 1) * listSize;
			end = pageNumber * listSize;
			DB db = DBFactory.getDB(uc.getDatasource());
			QueryParameters qp = new QueryParameters();
			qp.setFirstRow(0);
			qp.setMaxRows(listSize * pageNumber);
			String sql = UnitDataUtil.getSql(ac, uc, db);
			data = db.query(sql);
			resetData(uc, data, listSize, pageNumber);
		}
		String itemConfigs[] = StringUtil.split(uc.getSumConfig(), ";");
		for (int i = 0; i < itemConfigs.length; i++)
			items.add(getSumItem(uc, itemConfigs[i], begin, end));

		for (int i = 0; i < data.size(); i++) {
			net.wangit.Row row = data.getRow(i);
			for (int j = 0; j < items.size(); j++) {
				SumItem item = items.get(j);
				item.doSum(i, row);
			}

		}

	}

	public List getSumRows(int maxRowIndex, UnitComponent uc) {
		for (int i = 0; i < items.size(); i++) {
			SumItem item = items.get(i);
			List values = item.getSumValues();
			for (int j = 0; j < values.size(); j++)
				setSumValue(item, (SumValue) values.get(j), uc);

		}

		for (int i = 0; i < rows.size(); i++)
			((SumRow) rows.get(i)).setRowIndex(begin, maxRowIndex);

		Collections.sort(rows);
		for (int i = 0; i < rows.size(); i++)
			((SumRow) rows.get(i)).setRealRowIndex(i + 1);

		return rows;
	}

	private void setSumValue(SumItem item, SumValue sv, UnitComponent uc) {
		int rowIndex = sv.getRowIndex();
		String sumName = item.getSumName();
		String value = sv.getValue(uc.getElement(sumName));
		String text = item.getText(sv);
		String textName = item.getTextName();
		SumRow row = getSumRow(rowIndex, sumName, textName);
		if (!Checker.isEmpty(text) && Checker.isEmpty(textName))
			value = (new StringBuilder(String.valueOf(text))).append(value)
					.toString();
		row.setText(sumName, value);
		if (!Checker.isEmpty(text) && !Checker.isEmpty(textName))
			row.setText(textName, text);
	}

	private SumRow getSumRow(int rowIndex, String sumName, String textAtName) {
		for (int i = 0; i < rows.size(); i++) {
			SumRow row = (SumRow) rows.get(i);
			if (row.getRowIndex() == rowIndex && !row.isFilled(sumName)
					&& !row.isFilled(textAtName))
				return row;
		}

		SumRow row = new SumRow(rowIndex);
		rows.add(row);
		return row;
	}

	private SumItem getSumItem(UnitComponent uc, String itemConfig, int begin,
			int end) {
		int index = itemConfig.indexOf(SumConfig.HEAD);
		String type = itemConfig.substring(0, index + 1).trim().toUpperCase();
		String configs[] = StringUtil.split(itemConfig.substring(index + 1,
				itemConfig.indexOf(SumConfig.TAIL)), ",");
		if (configs.length < 2 || Checker.isEmpty(configs[1].trim()))
			throw new SumConfigurationException(uc.getDomain(), uc.getId());
		if (type.equals(SumConfig.S1))
			return new S1(uc, begin, end, configs);
		if (type.equals(SumConfig.S2))
			return new S2(uc, begin, end, configs);
		if (type.equals(SumConfig.S3))
			return new S3(uc, begin, end, configs);
		if (type.equals(SumConfig.C1))
			return new C1(uc, begin, end, configs);
		if (type.equals(SumConfig.C2))
			return new C2(uc, begin, end, configs);
		if (type.equals(SumConfig.C3))
			return new C3(uc, begin, end, configs);
		if (type.equals(SumConfig.A1))
			return new A1(uc, begin, end, configs);
		if (type.equals(SumConfig.A2))
			return new A2(uc, begin, end, configs);
		if (type.equals(SumConfig.A3))
			return new A3(uc, begin, end, configs);
		if (type.equals(SumConfig.P1))
			return new P1(uc, begin, end, configs);
		if (type.equals(SumConfig.P2))
			return new P2(uc, begin, end, configs);
		if (type.equals(SumConfig.P3))
			return new P3(uc, begin, end, configs);
		else
			throw new SumConfigurationException((new StringBuilder(
					"unsupported type ")).append(type).toString(), uc
					.getDomain(), uc.getId());
	}

	private void resetData(UnitComponent uc, MapList newData, int listSize,
			int pageNumber) {
		int maxSize = listSize * pageNumber;
		if (maxSize > newData.size())
			maxSize = newData.size();
		MapList data = new MapList();
		for (int i = listSize * (pageNumber - 1); i < maxSize; i++)
			data.add(newData.getRow(i));

		uc.setData(data);
	}
}
